package com.mp3.player
{
	import com.mp3.player.events.TrackListEvent;
	import com.mp3.player.views.Player;
	import com.mp3.player.vos.Track;
	import com.mp3.player.vos.TrackList;
	
	import flash.events.Event;
	import flash.external.ExternalInterface;
	import flash.trace.Trace;
	
	import mx.events.FlexEvent;
	import mx.utils.OnDemandEventDispatcher;
	
	import spark.components.Application;
	
	public class PlayerJSBridge extends Application
	{
		public var player:Player;
		
		//External API methods names-------------------------------------------------------------
		
		//method to add track to list
		public static const ADD_TRACK: String = "addTrack";
		
		//method to load track list
		public static const LOAD_TRACK_LIST: String = "loadTrackList";

		//method to add track list to list
		public static const ADD_TRACK_LIST: String = "addTrackList";
		
		//method to create new list
		public static const NEW_TRACK_LIST: String = "newTrackList";
		
		//method to create save list
		public static const SAVE_TRACK_LIST: String = "saveTrackList";
		
		//method to signalize JS un case some errors
		public static const FAULT: String = "fault";
		
		//method to handls TrackListEvent.ADD event
		public static const ADD_TRACK_HANDLER: String = "addTrackHandler";
		
		//method to pass url for xml in TLF format to show in advertasing panel
		public static const SET_ADVERT_SOURCE: String = "setAdvertSource";
		
		//End External API methods names----------------------------------------------------------
		
		/**
		 * Constructor
		*/
		public function PlayerJSBridge()
		{
			super();
			
			//add callbacks
			if (ExternalInterface.available)
			{
				ExternalInterface.addCallback(ADD_TRACK, addTrack);
				ExternalInterface.addCallback(ADD_TRACK_LIST, addTrackList);
				ExternalInterface.addCallback(NEW_TRACK_LIST, newTrackList);
				ExternalInterface.addCallback(SET_ADVERT_SOURCE, setAdvertSource);
			}
			else
			{
				//TODO what to do?
			}
		}
		
		/**
		 * @inheritDoc 
		 */		
		override protected function createChildren():void
		{
			super.createChildren();
			
			player.addEventListener(TrackListEvent.ADD, addTrackHandler);
			player.addEventListener(TrackListEvent.SAVE, saveTrackHandler);
			player.addEventListener(TrackListEvent.LOAD_TRACK_LIST, onLoadTrackList);
		}
		
		
		//------------------------------------------------------------------
		//
		//Callback methods
		//
		//------------------------------------------------------------------
		
		/**
		 * Function to add track to tracklist.
		 * Default value is null to avoid call without parameter.
		 * Value format is XML:
		 *  <track>
		 * 		<name></name>
		 * 		<artist></artist>
		 * 		<url></url>
		 * 		<lenght></lenght>
		 * 		<album></album>
		 * 		<albumUrl></albumUrl>
		 * 		<year></year>
		 * 		<genre></genre>
		 *  <track>
		*/
		private function addTrack(value: Object = null): void
		{
			var xml: XML = parseXML(value);
			var track: Track = deserializeTrack(xml);
			if (track != null)
			{
				player.addTrack(track);
			}
		}
		
		/**
		 * Function to add tracklist to tracklist.
		 * Default value is null to avoid call without parameter.
		 * Value format is XML:
		 *  <tracklist>
		 * 		<name></name>
		 * 		<tracks>
		 * 			<track>
		 * 				...
		 *  		<track>
		 * 			<track>
		 * 				...
		 * 			<track>
		 * 
		 * 			...
		 * 
		 * 		</tracks>
		 *  <tracklist>
		 */
		private function addTrackList(value: Object = null): void
		{
			var xml: XML = parseXML(value);
			var trackList: TrackList = deserializeTrackList(xml);
			if (trackList != null)
			{
				player.addTrackList(trackList);
			}
		}
		
		/**
		 * Function to create new tracklist.
		 * Default value is null to avoid call without parameter.
		 * Value format is XML:
		 *  <tracklist>
		 * 		<name></name>
		 * 		<tracks>
		 * 			<track>
		 * 				...
		 *  		<track>
		 * 			<track>
		 * 				...
		 * 			<track>
		 * 
		 * 			...
		 * 
		 * 		</tracks>
		 *  <tracklist>
		 */
		private function newTrackList(value: Object = null): void
		{
			var xml: XML = parseXML(value);
			var trackList: TrackList = deserializeTrackList(xml);
			if (trackList != null)
			{
				player.newTrackList(trackList);
			}
		}
		
		/**
		 * Function to pass source to xml file in TLF format to show in advertasing panel 
		 */		
		private function setAdvertSource(value: String): void
		{
			player.advertSource = value;	
		}
		
		//------------------------------------------------------------------
		//
		//Deserialize methods
		//
		//------------------------------------------------------------------
		private function parseXML(value: Object): XML
		{
			var xml: XML;
			
			try
			{
				xml = XML(value);
			}
			catch (error: Error)
			{
				fault(error.message);
			}
			
			return xml;
		}
		
		private function deserializeTrack(xml: XML): Track
		{
			var track: Track
			if (xml != null)
			{
				track = new Track();
				track.name = xml.name;
				track.artist = xml.artist;
				track.url = xml.url;
				track.length = xml.length;
				track.album = xml.album;
				track.albumUrl = xml.albumUrl;
				track.year = xml.year;
				track.genre = xml.genre;
			}
			
			return track;
		}
		
		private function deserializeTrackList(xml: XML): TrackList
		{
			var trackList: TrackList;
			if (xml != null)
			{
				trackList = new TrackList(xml.name);
				for each (var trackXML: XML in xml.tracks.*)
				{
					var track: Track = deserializeTrack(trackXML);
					if (track != null)
					{
						trackList.addTrack(track);
					}
				}
			}
			
			return trackList;
		}
		
		//------------------------------------------------------------------
		//
		// JS calling functions
		//
		//------------------------------------------------------------------
		/**
		 * Method call JS function fault  
		 * @param error
		 */		
		public function fault(error: String): void
		{
			if (ExternalInterface.available)
			{
				ExternalInterface.call(FAULT, error);
			}
		}
		
		/**
		 * Method to serialize tracklist in XML and call JS function  saveTrackList
		 */	
		public function saveTrackList(): void
		{
			if (ExternalInterface.available)
			{
				var trackList: TrackList = player.getTrackList();
				if (trackList != null)
				{
					var xml: XML = 
									<tracklist>
										<name>{trackList.name}</name>
										<tracks></tracks>
									</tracklist>;
					
					for each (var track: Track in trackList.tracks)
					{
						if (track != null)
						{
							var trackXML: XML = 
												<track>
													<name>{track.name}</name>
													<artist>{track.artist}</artist>
													<url>{track.url}</url>
													<length>{track.length}</length>
													<album>{track.album}</album>
													<albumUrl>{track.albumUrl}</albumUrl>
													<year>{track.year}</year>
													<genre>{track.genre}</genre>
												</track>
							
							xml.tracks.appendChild(trackXML);
						}
					}
					
					ExternalInterface.call(SAVE_TRACK_LIST, xml.toString());
				}
			}
		}
		
		//------------------------------------------------------------------
		//
		// Event handlers
		//
		//------------------------------------------------------------------
		/**
		 * Add new track request handler.
		 *  
		 * @param event TrackListEvent
		 */		
		private function addTrackHandler(event:TrackListEvent):void
		{
			// add new track
			if (ExternalInterface.available)
			{
				ExternalInterface.call(ADD_TRACK_HANDLER);
			}
		}
		
		/**
		 * Save track list request handler.
		 *  
		 * @param event TrackListEvent
		 */	
		private function saveTrackHandler(event:TrackListEvent):void
		{
			saveTrackList();
		}
		
		/**
		 * Load track list handler.
		 *  
		 * @param event TrackListEvent
		 */		
		private function onLoadTrackList(event: TrackListEvent): void
		{
			if (ExternalInterface.available)
			{
				ExternalInterface.call(LOAD_TRACK_LIST);
			}
		}
		
	}
}